package org.mihalovic.PES.GUI;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Component;
import java.awt.GridLayout;

import edu.uci.ics.jung.algorithms.layout.FRLayout;
import edu.uci.ics.jung.algorithms.layout.CircleLayout;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.algorithms.layout.SpringLayout;
import edu.uci.ics.jung.graph.DirectedSparseGraph;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.layout.LayoutTransition;
import edu.uci.ics.jung.visualization.util.Animator;

import org.mihalovic.PES.Core.Graph.*;



/**
 * A panel to show graph of Porada members with PageRank scores
 * @author Administrator
 */
public class VisualGraphPanel extends JPanel {
    private VisualizationViewer<Node, Edge> vv;
    private DirectedSparseGraph<Node, Edge> graph;
    private double maxRank;
    
    private JLabel infoLabel;
    private JPanel upperPanel;
    private JButton drawGraphButton;

    private Class<? extends Layout> graphLayout;

    
    
    /**
     * @param rankedGraph a graph with ranks assigned (may be zeros if before any ranking)
     */
    public VisualGraphPanel() {

        upperPanel = new JPanel(new GridLayout(1, 1));
        upperPanel.setBackground(java.awt.Color.GRAY);
        
        JPanel lowerPanel = new JPanel();
        lowerPanel.setLayout(new BorderLayout());
        lowerPanel.setMinimumSize(new Dimension(30, 30));
        lowerPanel.setMaximumSize(new Dimension(10240, 30));
        
        JPanel lowerRightPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        lowerRightPanel.setMinimumSize(new Dimension(30, 30));

        infoLabel = new JLabel();
        JPanel infoPanel = new JPanel();
        infoPanel.add(infoLabel);

        JComboBox layoutCombo = new JComboBox();
        layoutCombo.setModel(new DefaultComboBoxModel(getLayouts()));
        layoutCombo.setRenderer(new DefaultListCellRenderer() {
            @Override
            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
                String valueString = value.toString();
                valueString = valueString.substring(valueString.lastIndexOf('.')+1);
                return super.getListCellRendererComponent(list, valueString, index, isSelected, cellHasFocus);
            }
        });
        layoutCombo.addActionListener(new LayoutChooser(layoutCombo));
        layoutCombo.setSelectedItem(FRLayout.class);

        
        drawGraphButton = new JButton("Show graph");
        drawGraphButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
//                if(graph != null && graph.getVertexCount() > 0)
                showGraph();
            }
        });

        lowerRightPanel.add(layoutCombo);
        lowerRightPanel.add(drawGraphButton);
        
        lowerPanel.add(infoPanel, BorderLayout.LINE_START);
        lowerPanel.add(lowerRightPanel, BorderLayout.LINE_END);

        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        add(upperPanel);
        add(lowerPanel);
    }
    
    
    public void setGraph(DirectedSparseGraph<Node, Edge> graph, double maxRank) {
        this.graph = graph;
        this.maxRank = maxRank;
    }
    
    /** Dispose the graph */
    public void Clear() {
        upperPanel.removeAll();
        upperPanel.revalidate();
        upperPanel.repaint();
        setGraph(null, 0.0);
        infoLabel.setText("");
    }


    private void showGraph() {
        if(graph==null)
            graph = GraphHolder.GetUnrankedGraph();

        Constructor constructor;
        Layout l=null;
        try {
            constructor = graphLayout.getConstructor(new Class[]{Graph.class});
            Object o = constructor.newInstance(graph);
            l = (Layout) o;
        } catch (Exception e) {
            Logger.getLogger(VisualGraphPanel.class.getName()).log(Level.SEVERE, null, e);
        }

        vv = new VisualizationViewer<Node, Edge>(l);
        SimpleGraphViewer sgv = new SimpleGraphViewer/*<Integer, Edge>*/(vv, maxRank);
        upperPanel.removeAll();

        vv.setSize(upperPanel.getSize());
        upperPanel.add(sgv);

        infoLabel.setText("Showing graph: " + graph.getVertexCount() + " users, " + graph.getEdgeCount() + " aggregated 'useful' edges.");
        l.setSize(vv.getSize());
        upperPanel.revalidate();
        upperPanel.repaint();
    }


    @SuppressWarnings("unchecked")
    private Class<? extends Layout> [] getLayouts() {
        List<Class<?>> layouts = new ArrayList<Class<?>>();
        layouts.add(CircleLayout.class);
        layouts.add(SpringLayout.class);
        layouts.add(FRLayout.class);
        return layouts.toArray(new Class[0]);
    }
    
    
    final class LayoutChooser implements ActionListener {
        private final JComboBox jcb;

        private LayoutChooser(JComboBox jcb) {
            super();
            this.jcb = jcb;
        }

        public void actionPerformed(ActionEvent ae) {
            Class layoutC = (Class) jcb.getSelectedItem();
            Class lay = layoutC;
            graphLayout = layoutC;
            try
            {
                @SuppressWarnings("unchecked")
                Constructor constructor = lay.getConstructor(new Class[] {Graph.class});
                if(vv==null)            //should happen only on GUI initialization
                    return;
                Object o = constructor.newInstance(vv.getGraphLayout().getGraph());
                Layout l = (Layout) o;

                l.setInitializer(vv.getGraphLayout());
                l.setSize(vv.getSize());

                LayoutTransition<Node, Edge> lt = new LayoutTransition<Node, Edge>(vv, vv.getGraphLayout(), l);
                Animator animator = new Animator(lt);
                animator.start();
                vv.getRenderContext().getMultiLayerTransformer().setToIdentity();
                vv.repaint();

            }
            catch (Exception e) {
                System.err.println(e.getMessage() + ":\n" + e.getStackTrace());
            }
        }
    }
}
